# -*- coding: utf-8 -*
"""
Areas are special tags for tiles. In theory you can have in infinite number of tags
on a tile, and 20 areas attached to it.

But there are some areas that are exclusive, e.g. when you don�t want a village area
to occupy same space as a wood area. 
On the other hand you want a hunting area for a hunter overlap multiple woods and other areas.

Areas are commonly used in the game and this class deals with all the tagging and bookkeeping
involved.

Areas are defined by their center piece and occupy tiles in various ways around
this center-tile.
Area can be defined as rectangles, circles or in a random way. 
They can grow or shrink and any tile can be attached to them.
Area objects handle the grid registry for you.

Currently 1 tile can be only part of 1 area, so that means when you have 2 kinds
of areas e.g. villages or wood you have to avoid conflicts when they grow. 

There is a (optional) conflict detection, so when a area grows (or shrinks) it does 
not override an existing area.

To enable this conflict resolution we organize areas in area groups and define the rule
that 2 members of the same area group can not be assigned to 1 tile.
 
"""

import grid
import pygame
import random

class AreaGroup (object):
    def  __init__(self, name):
        self.name == name
        self.area = []
        
    def add_area (self, area):
        "Add a area to group, returns false if it is already in"
        if not area in self.area:
            self.area.append (area)
            return True
        return False
    def del_area (self, area):
        "remove area from group, returns false if it wasn´t in"
        try:
            self.area.remove(area)
        except:
            return False
        return True
    
class Area (object):
    def __init__ (self, grid, prename, id, center):
        self.id = id
        self._grid = grid
        self.prename = prename
        self.name = prename + str(id)
        self.rect = pygame.Rect ((center),(1,1))
        self._grid.register (self._grid.get_tile_at_tilepos(self.rect.topleft), self.name)

    def area_grow (self, percent_to_grow=50):
        """
        loop over all tiles of the wood and randomly grow the are to 
        neighbor tiles (if they are not occupied yet)
        """
        tiles = [t for t in self._grid.get_objs_for_tag (self.name) if isinstance (t, grid.Tile)]
        for t in tiles:
            # get neighbor tiles of current tile - without tags
            neigh = [i for i in self._grid.get_neighbour_tiles (t) if not self._grid.has_tag (i, self.name)]
            for n in neigh:
                r = random.randint (0,100)
                if r < percent_to_grow:
                    self._grid.register (n, self.name)

    def area_rectangle (self, size):
        """ 
        set an rectangle area starting at w/2,h/2 of the center with size w,h
        """
        w, h= size
        w2, h2 = w/2, h/2
        self.rect.topleft = self.rect.x - w2, self.rect.y - h2
        self.rect.size = w,h
        self.update_area_tagging()
        
    def overlap (self, area2):
        if self.rect.colliderect (area2.rect): 
            return True
        return False
        
    def update_area_tagging (self):
        """
        cleanup and update tag register based on infos in self.rect
        TODO: check for group conflicts???
        """ 
        #clean up all tags
        self._grid.flush_register_by_tag (self.name)
        #tag new area based on self.rect
        for y in range(self.rect.y,self.rect.y + self.rect.height):
            for x in range (self.rect.x,self.rect.x + self.rect.width):
                t = self._grid.get_tile_at_tilepos ((x,y))
                self._grid.register (t, self.name)
 
   # clean me up and recode me nicer
    def find_points_distance(self, number, mindist):
        """
        find "number" random spots in an area with a minimum 
        distance of "mindist" tiles to each other
        """
        max_iter = 1000     # emergency break
        points = []
        tiles = self._grid.get_objs_for_tag (self.name)
        r = random.randint(0,(len(tiles)-1))
        points.append(tiles[r])
        c = 0
        while len(points) < number and c < max_iter:
            p = tiles[random.randint(0,(len(tiles)-1))]
            add = True
            for p2 in points:
                if p2 == None: continue
                if self._grid.get_tile_distance (p2, p) < mindist:
                    add = False
            if add and p != None: points.append(p)
            c+=1
        return points


if __name__ == "__main__":
    g = grid.Pathfinding_Grid ((0,0), 100, 100, (20,20))
    a = Area (g, 1, (10,10))
    g.print_tag_register()
    a.area_rectangle ((5,5))
    g.print_tag_register()